<?php
/*********************************************
 *  CPG Dragonfly™ CMS
 *********************************************
	Copyright © since 2010 by CPG-Nuke Dev Team
	http://dragonflycms.org

	Dragonfly is released under the terms and conditions
	of the GNU GPL version 2 or any later version

	XRI Resolution 2.0
	http://docs.oasis-open.org/xri/2.0/specs/cd02/xri-resolution-V2.0-cd-02.pdf
*/

namespace Poodle\Yadis;

abstract class XRI
{
	const
		// XRIs Reserved Namespaces for XRI Resolution
		NS_RES     = 'xri://$res',
		NS_XRD     = 'xri://$xrd',
		NS_XRD_2_0 = 'xri://$xrd*($v*2.0)',
		NS_XRDS    = 'xri://$xrds',

		// XRIs Assigned Namespaces to XRI Resolution Service Types
		NS_RES_AUTH      = 'xri://$res*auth',
		NS_RES_AUTH_2_0  = 'xri://$res*auth*($v*2.0)',
		NS_RES_PROXY     = 'xri://$res*proxy',
		NS_RES_PROXY_2_0 = 'xri://$res*proxy*($v*2.0)',

		MIME_XRD      = 'application/xrd+xml',
		MIME_XRDS     = 'application/xrds+xml',
		MIME_URI_LIST = 'text/uri-list';

	public static function getAuthorities()
	{
		return array('!', '=', '@', '+', '$', '(');
	}

	/**
	 * Mime parameters must be seperated with percent-encoded semicolon
	 * https         FALSE
	 * saml          FALSE
	 * refs          TRUE
	 * sep           FALSE
	 * nodefault_t   TRUE
	 * nodefault_p   TRUE
	 * nodefault_m   TRUE
	 * uric          FALSE
	 * cid           TRUE
	 *
	 * http://xri.net/{QXRI}?_xrd_r=application%2Fxrds%2Bxml&_xrd_t=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fserver
	 * http://xri.net/{QXRI}?_xrd_r=application%2Fxrds%2Bxml&_xrd_t=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fsignon
	 * http://xri.net/{QXRI}?_xrd_r=application%2Fxrds%2Bxml&_xrd_t=http%3A%2F%2Fopenid.net%2Fsignon%2F1.2
	 * http://xri.net/{QXRI}?_xrd_r=application%2Fxrds%2Bxml&_xrd_t=http%3A%2F%2Fopenid.net%2Fsignon%2F1.1
	 * http://xri.net/{QXRI}?_xrd_r=application%2Fxrds%2Bxml&_xrd_t=http%3A%2F%2Fopenid.net%2Fsignon%2F1.0
	 */
	public static function resolve($xri, \Poodle\HTTP\Request $fetcher, $filters = array(), $service_types=array(null), $proxy_url = 'http://xri.net/')
	{
		$services = array();
		$CanonicalID = null;
		foreach ($service_types as $service_type)
		{
			// trim off the xri:// prefix
			$qxri = substr(self::toURINormal($xri), 6);
			$hxri = $proxy_url . $qxri;
			$args = array('_xrd_r' => 'application/xrds+xml');
			if ($service_type) {
				$args['_xrd_t'] = $service_type;
			} else {
				// Perform service endpoint selection.
//				$args['_xrd_r'] .= ';sep=true';
			}
			$url = \Poodle\URI::appendArgs($hxri, $args);

			$response = $fetcher->get($url);
			if (!$response) { return false; }
			if (200 != $response->status && 206 != $response->status) {
				// 210/211: invalid QXRI
				// 212-214: invalid parameters
				// 216:     unknown community root authority
				continue;
			}
			$XRDS = XRDS::parseXML($response->body);
			if (!$XRDS) {
				continue;
			}

			// http://openid.net/specs/openid-authentication-2_0.html#rfc.section.7.3.2.3
			$CanonicalID = $XRDS->getCanonicalID($xri);
			if (false === $CanonicalID) { return false; }
			$ProviderID  = $XRDS->getProviderID();
			if (false === $ProviderID ) { return false; }

			$services = array_merge($services, $XRDS->services($filters));
			/**
			 * TODO:
			 * If we do get hits for multiple service_types, we're
			 * almost certainly going to have duplicated service
			 * entries and broken priority ordering.
			 */
		}
		return array(
			'CanonicalID' => $CanonicalID,
			'Services' => $services
		);
	}

	protected static function escapeXref($xref_match)
	{
		return str_replace(
			array('#'  ,'?'  ,'/'),
			array('%23','%3F','%2F'),
			$xref_match[0]);
	}

	protected static function toURINormal($xri)
	{
		// Escape for IRI
		return preg_replace_callback('/\((.*?)\)/', 'Poodle\\Yadis\\XRI::escapeXref', str_replace('%', '%25', self::URI($xri)));
	}

	public static function URI($xri)
	{
		return (0 === strpos($xri, 'xri://')) ? $xri : 'xri://'.$xri;
	}

}
